package com.yeziji.devops.sql.constructor;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.yeziji.devops.constant.SqlExecuteTypeEnum;
import com.yeziji.devops.constant.SqlForeignRelationEnum;
import com.yeziji.devops.sql.SqlBuilderFactory;
import com.yeziji.devops.sql.base.SqlConstructorBase;
import com.yeziji.devops.sql.info.CreateTableInfo;
import com.yeziji.devops.sql.info.ForeignKeyInfo;
import com.yeziji.devops.sql.info.IndexKeyInfo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;

import javax.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.List;

/**
 * 创建 sql 构造器
 *
 * <p>用于创建数据库、数据表
 *
 * @author gzkemays
 * @since 2023/01/13 11:19 AM
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder(toBuilder = true)
@EqualsAndHashCode(callSuper = true)
public class CreateSqlConstructor extends SqlConstructorBase {
    /**
     * 创建的类型
     * <p>
     * 创建数据表或者数据库
     * </p>
     * <pre>
     *     table | database
     * </pre>
     */
    @NotBlank(message = "必须指定创建的类型")
    private String create;

    /**
     * 指定数据源
     * <p>
     * 若选择的数据源没有指定数据库，那么可以通过该属性指定数据库进行建表
     * </p>
     */
    private String database;

    /**
     * 是否追加判断删除
     * <p>
     * 像类似于 create table 追加判断 DROP TABLE IF EXISTS `test`
     * </p>
     * <pre>
     *     table | database
     * </pre>
     */
    private boolean existsDrop;

    /**
     * 创建的名称
     */
    @NotBlank(message = "必须指定创建的名称")
    private String name;

    /**
     * 创建的对象
     * <p>
     * 作用于 create table
     * </p>
     */
    private List<CreateTableInfo> fields;

    /**
     * 外键引用对象
     */
    private List<ForeignKeyInfo> foreignKeys;

    /**
     * 索引引用对象
     */
    private List<IndexKeyInfo> indexKeys;

    /**
     * 存储引擎
     * <p>
     * 这里在构建不做约束，需要用户自己判断，但是可以通过调用 getEngine 获取支持的存储引擎
     * </p>
     */
    private String engine;

    /**
     * 数据表字符集
     * <p>
     * 这里在构建不做约束，需要用户自己判断，但是可以通过调用 getCharacter 获取支持的字符集
     * </p>
     */
    private String character;

    /**
     * 排序方式
     * <p>
     * 这里在构建不做约束，需要用户自己判断，但是可以通过调用 getCollate 获取支持的排序方式
     * </p>
     */
    private String collate;

    /**
     * 描述
     */
    private String comment;

    /**
     * 行格式
     * <p>
     * 这里在构建不做约束，需要用户自己判断，但是可以通过调用 getRowFormat 获取支持的行格式
     * </p>
     */
    private String rowFormat;

    @Override
    protected void check() {
        super.setType(SqlExecuteTypeEnum.CREATE.getValue());
    }

    @Override
    public String buildSql() {
        if (StrUtil.isNotBlank(super.sql)) {
            return super.sql;
        }

        this.check();
        return new SqlBuilderFactory().getSqlBuilder(SqlExecuteTypeEnum.CREATE, this).execute();
    }

    public static void main(String[] args) {
        List<CreateTableInfo> fields = new ArrayList<>();
        fields.add(
                CreateTableInfo.builder()
                        .name("id")
                        .type("int")
                        .size(11)
                        .comment("主键")
                        .autoIncrement(true)
                        .acceptNull(false)
                        .primary(true)
                        .build());
        fields.add(
                CreateTableInfo.builder()
                        .name("userId")
                        .type("int")
                        .size(11)
                        .comment("用户id")
                        .acceptNull(false)
                        .build());
        fields.add(
                CreateTableInfo.builder().name("author").type("varchar").size(255).comment("作者").build());
        fields.add(CreateTableInfo.builder().name("content").type("longtext").comment("内容").build());
        fields.add(
                CreateTableInfo.builder()
                        .name("tempSave")
                        .type("tinyint")
                        .size(1)
                        .defaultValue(1)
                        .comment("是否暂存")
                        .build());
        fields.add(
                CreateTableInfo.builder()
                        .name("createTime")
                        .type("datetime")
                        .currentTimestamp(true)
                        .comment("创建时间")
                        .build());

        List<ForeignKeyInfo> foreignKeys = new ArrayList<>();
        List<String> foreignKeyFields = new ArrayList<>();
        foreignKeyFields.add("userId");
        List<String> referencesFields = new ArrayList<>();
        referencesFields.add("id");
        foreignKeys.add(
                ForeignKeyInfo.builder()
                        .name("id to id")
                        .foreignKeyFields(foreignKeyFields)
                        .referencesTable("test1")
                        .referencesFields(referencesFields)
                        .updateMethod(SqlForeignRelationEnum.CASCADE.getValue())
                        .deleteMethod(SqlForeignRelationEnum.CASCADE.getValue())
                        .build());

        List<IndexKeyInfo> indexKeys = new ArrayList<>();
        List<String> indexFields = new ArrayList<>();
        indexFields.add("userId");
        indexKeys.add(
                IndexKeyInfo.builder().name("userId").comment("查询用户 id 索引").fields(indexFields).build());
        CreateSqlConstructor build =
                CreateSqlConstructor.builder()
                        .create("table")
                        .name("test")
                        .comment("测试生成表")
                        .character("utf8mb4")
                        .collate("utf8mb4_0900_ai_ci")
                        .existsDrop(true)
                        .fields(fields)
                        .foreignKeys(foreignKeys)
                        .indexKeys(indexKeys)
                        .build();
        System.out.println(
                CreateSqlConstructor.builder()
                        .create("table")
                        .name("test")
                        .comment("测试生成表")
                        .character("utf8mb4")
                        .collate("utf8mb4_0900_ai_ci")
                        .existsDrop(true)
                        .fields(fields)
                        .foreignKeys(foreignKeys)
                        .indexKeys(indexKeys)
                        .build()
                        .buildSql());
        System.out.println(JSONUtil.toJsonStr(build));
        System.out.println(
                JSONUtil.toJsonStr(
                        CreateSqlConstructor.builder().create("database").name("testinter").build()));
    }
}
